package org.amphiprion.diceroller.screens;

import java.util.HashMap;
import java.util.List;

import org.amphiprion.diceroller.R;
import org.amphiprion.diceroller.TagObject;
import org.amphiprion.diceroller.entity.DiceDefinition;
import org.amphiprion.diceroller.entity.DiceFaceDefinition;
import org.amphiprion.diceroller.entity.GameDice;
import org.amphiprion.diceroller.entity.GameDiceFace;
import org.amphiprion.diceroller.entity.GameDiceFaceSymbole;
import org.amphiprion.diceroller.entity.GameSymbole;
import org.amphiprion.diceroller.screens.animation.Rotate3DAnimation;
import org.amphiprion.diceroller.screens.animation.ScaleTranslate3DAnimation;
import org.amphiprion.diceroller.util.DiceUtil;
import org.amphiprion.gameengine.GameScreen;
import org.amphiprion.gameengine.Image2D;
import org.amphiprion.gameengine.Mesh;
import org.amphiprion.gameengine.ScreenProperty;
import org.amphiprion.gameengine.animation.Scale2DAnimation;

import android.content.Context;
import android.view.MotionEvent;
import android.view.animation.BounceInterpolator;
import android.view.animation.DecelerateInterpolator;

public class ChooseDiceFaceScreen extends GameScreen {
	private List<Mesh> selectedDices;
	private HashMap<String, DiceDefinition> diceDefinitions;
	private float tmpX;
	private float tmpY;
	private float tmpZ;
	private float tmpRotX;
	private float tmpRotY;
	private float tmpRotZ;
	private float tmpScale;

	private int currentDiceIndex = 0;
	private Image2D btOk;
	private Image2D btCancel;
	private CallBack callback;

	private ScaleTranslate3DAnimation centerToDock = null;
	private ScaleTranslate3DAnimation dockToCenter = null;
	private Rotate3DAnimation rotateAnimation = null;

	private DecelerateInterpolator itpDecel = new DecelerateInterpolator();

	public ChooseDiceFaceScreen(Context context, HashMap<String, DiceDefinition> diceDefinitions, List<Mesh> selectedDices, CallBack callback) {
		this.selectedDices = selectedDices;
		this.diceDefinitions = diceDefinitions;
		this.callback = callback;
		computePositionning(true);

		Image2D bg = new Image2D(context, "D" + R.drawable.bg_choose_face);
		bg.x = 768 / 2;
		bg.y = 1280 / 2;

		backgroundObjects2d.add(bg);

		btOk = new Image2D(context, "D" + R.drawable.ok);
		btOk.x = 159;
		btOk.y = 993;
		objects2d.add(btOk);

		btCancel = new Image2D(context, "D" + R.drawable.cancel);
		btCancel.x = 613;
		btCancel.y = 993;
		objects2d.add(btCancel);
	}

	private void computePositionning(boolean useOriginalValue) {
		for (int i = 0; i < selectedDices.size(); i++) {
			Mesh m = selectedDices.get(i);
			TagObject tag = (TagObject) m.getTagObject();
			if (i < currentDiceIndex) {
				float width = (currentDiceIndex) * 0.7f;
				float startoffset;
				startoffset = -(width - 0.7f) / 2;
				tag.alternateCoordinate[0] = startoffset + 0.8f * (currentDiceIndex - i - 1);
				tag.alternateCoordinate[1] = 2.0f;
				tag.alternateCoordinate[2] = 0;
				tag.alternateScale = 0.5f;
			} else if (i == currentDiceIndex) {
				tag.alternateCoordinate[0] = 0;
				tag.alternateCoordinate[1] = 0f;
				tag.alternateCoordinate[2] = 0;
				tag.alternateScale = 1.5f;
			} else if (i > currentDiceIndex) {
				float width = (selectedDices.size() - currentDiceIndex - 1) * 0.7f;
				float startoffset;
				// if ((selectedDices.size() - currentDiceIndex - 1) % 2 == 0) {
				startoffset = -(width - 0.7f) / 2;
				// } else {
				// startoffset = -(width / 2 - 0.4f);
				//
				// }
				tag.alternateCoordinate[0] = startoffset + 0.8f * (i - currentDiceIndex - 1);
				tag.alternateCoordinate[1] = -2.0f;
				tag.alternateCoordinate[2] = 0;
				tag.alternateScale = 0.5f;
			}
			if (useOriginalValue) {
				tag.alternateRotation[0] = m.rotXDegree;
				tag.alternateRotation[1] = m.rotYDegree;
				tag.alternateRotation[2] = m.rotZDegree;
				tag.alternaleFaceNumber = DiceUtil.getResultFaceNumber(diceDefinitions, m);
			}

		}

	}

	@Override
	public boolean isLayered() {
		return true;
	}

	@Override
	public void onDraw3D(float[] mMVPMatrix, float[] mViewMatrix, float[] mModelMatrix, float[] mProjectionMatrix, float[] mLightPosInEyeSpace) {
		super.onDraw3D(mMVPMatrix, mViewMatrix, mModelMatrix, mProjectionMatrix, mLightPosInEyeSpace);
		btOk.rotationDegree = view.getScreenProperty().deviceAngle;
		btCancel.rotationDegree = view.getScreenProperty().deviceAngle;
		for (Mesh m : selectedDices) {
			TagObject tag = (TagObject) m.getTagObject();
			tmpX = m.X;
			tmpY = m.Y;
			tmpZ = m.Z;
			tmpRotX = m.rotXDegree;
			tmpRotY = m.rotYDegree;
			tmpRotZ = m.rotZDegree;
			tmpScale = m.scale;

			m.X = tag.alternateCoordinate[0];
			m.Y = tag.alternateCoordinate[1];
			m.Z = tag.alternateCoordinate[2];
			m.rotXDegree = tag.alternateRotation[0];
			m.rotYDegree = tag.alternateRotation[1];
			m.rotZDegree = tag.alternateRotation[2];
			m.scale = tag.alternateScale;

			m.draw(mMVPMatrix, mViewMatrix, mModelMatrix, mProjectionMatrix, mLightPosInEyeSpace);

			m.X = tmpX;
			m.Y = tmpY;
			m.Z = tmpZ;
			m.rotXDegree = tmpRotX;
			m.rotYDegree = tmpRotY;
			m.rotZDegree = tmpRotZ;
			m.scale = tmpScale;
		}
	}

	@Override
	public boolean backRequested() {
		view.removeScreen(1);
		callback.diceCanceled();
		return false;
	}

	private int lastTouchX;
	private int lastTouchY;
	private boolean touchMove = false;
	private boolean disableTouch;

	@Override
	public void onTouch(MotionEvent event) {
		if (disableTouch) {
			return;
		}
		ScreenProperty sp = view.getScreenProperty();

		int nx = (int) (event.getX() / sp.screenScaleX);
		int ny = (int) (event.getY() / sp.screenScaleY);
		if (event.getAction() == MotionEvent.ACTION_DOWN) {
			lastTouchX = nx;
			lastTouchY = ny;
			touchMove = false;
		} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
			if (ny >= 480 && ny <= 795) {
				int deltaX = nx - lastTouchX;
				int deltaY = ny - lastTouchX;
				if (!touchMove && Math.abs(deltaX) < 10 && Math.abs(deltaY) < 10) {
					return;
				}
				touchMove = true;
			}
		} else if (event.getAction() == MotionEvent.ACTION_UP) {
			if (!touchMove) {
				if (btOk.contains(nx, ny)) {
					disableTouch = true;
					Scale2DAnimation anim = new Scale2DAnimation(btOk, 700, 0, 0.5f, 1);
					anim.setInterpolation(new BounceInterpolator());

					addAnimation(anim);
					postDelayed(new Runnable() {

						@Override
						public void run() {
							for (Mesh m : selectedDices) {
								TagObject tag = (TagObject) m.getTagObject();

								m.rotXDegree = tag.alternateRotation[0];
								m.rotYDegree = tag.alternateRotation[1];
								m.rotZDegree = tag.alternateRotation[2];
								tag.selected = false;
							}
							callback.diceUpdated();
							view.removeScreen(1);
						}
					}, 700);
				} else if (btCancel.contains(nx, ny)) {
					disableTouch = true;
					Scale2DAnimation anim = new Scale2DAnimation(btCancel, 700, 0, 0.5f, 1);
					anim.setInterpolation(new BounceInterpolator());

					addAnimation(anim);
					postDelayed(new Runnable() {

						@Override
						public void run() {
							callback.diceCanceled();
							view.removeScreen(1);
						}
					}, 700);
				}
			} else {
				if (Math.abs((nx - lastTouchX) / 2) > Math.abs(ny - lastTouchY)) {
					if (rotateAnimation != null) {
						rotateAnimation.finish();
						removeAnimation(rotateAnimation);
						rotateAnimation = null;
					}
					Mesh m = selectedDices.get(currentDiceIndex);
					TagObject tag = (TagObject) m.getTagObject();
					float[] startRot = new float[] { tag.alternateRotation[0], tag.alternateRotation[1], tag.alternateRotation[2] };

					DiceDefinition dd = diceDefinitions.get(tag.gameDice.getType());
					DiceFaceDefinition newDfd = null;
					if (nx - lastTouchX > 0) {
						newDfd = dd.getNextFaceDefinition(tag.alternaleFaceNumber, true);
					} else {
						newDfd = dd.getPreviousFaceDefinition(tag.alternaleFaceNumber, true);
					}
					int faceIndex = dd.getFaceDefinitions().indexOf(newDfd);
					tag.alternateRotation = DiceUtil.getRotationToFace(diceDefinitions, tag.gameDice, faceIndex);

					// Log.d(ApplicationConstants.PACKAGE, "FACE avant:" + tag.alternaleFaceNumber + "   apres:" + newDfd.getNumber());
					tag.alternaleFaceNumber = newDfd.getNumber();

					float[] endRot = new float[] { tag.alternateRotation[0], tag.alternateRotation[1], tag.alternateRotation[2] };
					rotateAnimation = new Rotate3DAnimation(m, true, 300, 0, startRot, endRot);
					rotateAnimation.setInterpolation(itpDecel);
					addAnimation(rotateAnimation);

					computeDeltaFaceSymbole();

				} else if (Math.abs((ny - lastTouchY) / 2) > Math.abs(nx - lastTouchX)) {

					if (centerToDock != null) {
						centerToDock.finish();
						removeAnimation(centerToDock);
						centerToDock = null;
					}
					if (dockToCenter != null) {
						dockToCenter.finish();
						removeAnimation(dockToCenter);
						dockToCenter = null;
					}
					Mesh curr = selectedDices.get(currentDiceIndex);
					Mesh newCurr = null;
					float[] newCurrStartCoord = new float[3];
					if (ny - lastTouchY < 0) {
						if (currentDiceIndex < selectedDices.size() - 1) {
							currentDiceIndex++;
							newCurr = selectedDices.get(currentDiceIndex);
							newCurrStartCoord[0] = ((TagObject) newCurr.getTagObject()).alternateCoordinate[0];
							newCurrStartCoord[1] = ((TagObject) newCurr.getTagObject()).alternateCoordinate[1];
							newCurrStartCoord[2] = ((TagObject) newCurr.getTagObject()).alternateCoordinate[2];
							computePositionning(false);
						} else {
							touchMove = false;
							return;
						}
					} else {
						if (currentDiceIndex > 0) {
							currentDiceIndex--;
							newCurr = selectedDices.get(currentDiceIndex);
							newCurrStartCoord[0] = ((TagObject) newCurr.getTagObject()).alternateCoordinate[0];
							newCurrStartCoord[1] = ((TagObject) newCurr.getTagObject()).alternateCoordinate[1];
							newCurrStartCoord[2] = ((TagObject) newCurr.getTagObject()).alternateCoordinate[2];
							computePositionning(false);
						} else {
							touchMove = false;
							return;
						}
					}
					centerToDock = new ScaleTranslate3DAnimation(curr, true, 300, 0, new float[] { 0, 0, 0 }, new float[] { ((TagObject) curr.getTagObject()).alternateCoordinate[0], ((TagObject) curr.getTagObject()).alternateCoordinate[1],
							((TagObject) curr.getTagObject()).alternateCoordinate[2] }, 1.5f, 0.5f);
					centerToDock.setInterpolation(itpDecel);
					((TagObject) curr.getTagObject()).alternateCoordinate[0] = 0;
					((TagObject) curr.getTagObject()).alternateCoordinate[1] = 0;
					((TagObject) curr.getTagObject()).alternateCoordinate[2] = 0;
					((TagObject) curr.getTagObject()).alternateScale = 1.5f;
					addAnimation(centerToDock);

					dockToCenter = new ScaleTranslate3DAnimation(newCurr, true, 300, 0, newCurrStartCoord, new float[] { 0, 0, 0 }, 0.5f, 1.5f);
					dockToCenter.setInterpolation(itpDecel);
					((TagObject) newCurr.getTagObject()).alternateCoordinate[0] = newCurrStartCoord[0];
					((TagObject) newCurr.getTagObject()).alternateCoordinate[1] = newCurrStartCoord[1];
					((TagObject) newCurr.getTagObject()).alternateCoordinate[2] = newCurrStartCoord[2];
					((TagObject) newCurr.getTagObject()).alternateScale = 0.5f;

					addAnimation(dockToCenter);
				}
			}
			touchMove = false;
		}
	}

	private void computeDeltaFaceSymbole() {
		HashMap<GameSymbole, Float> valuePerSymboles = new HashMap<GameSymbole, Float>();
		// original symboles for selected dices
		for (int i = 0; i < selectedDices.size(); i++) {
			Mesh die = selectedDices.get(i);
			TagObject tag = (TagObject) die.getTagObject();
			GameDice gameDice = tag.gameDice;

			String selectedFaceNumber = tag.originalFaceNumber;
			if (selectedFaceNumber != null) {
				// Log.d(ApplicationConstants.PACKAGE, "++ " + gameDice.getId() + "  facenumber=" + selectedFaceNumber);
				GameDiceFace face = gameDice.getDiceFaces().get(selectedFaceNumber);
				for (GameDiceFaceSymbole gdfc : face.getFaceSymboles()) {
					Float value = valuePerSymboles.get(gdfc.getSymbole());
					if (value != null) {
						value = Float.valueOf(value - gdfc.getValue());
					} else {
						value = Float.valueOf(-gdfc.getValue());
					}
					valuePerSymboles.put(gdfc.getSymbole(), value);

				}
			}
		}

		// original symboles for selected dices
		for (int i = 0; i < selectedDices.size(); i++) {
			Mesh die = selectedDices.get(i);
			TagObject tag = (TagObject) die.getTagObject();
			GameDice gameDice = tag.gameDice;

			String selectedFaceNumber = tag.alternaleFaceNumber;
			if (selectedFaceNumber != null) {
				// Log.d(ApplicationConstants.PACKAGE, "++ " + gameDice.getId() + "  facenumber=" + selectedFaceNumber);
				GameDiceFace face = gameDice.getDiceFaces().get(selectedFaceNumber);
				for (GameDiceFaceSymbole gdfc : face.getFaceSymboles()) {
					Float value = valuePerSymboles.get(gdfc.getSymbole());
					if (value != null) {
						value = Float.valueOf(value + gdfc.getValue());
					} else {
						value = Float.valueOf(gdfc.getValue());
					}
					valuePerSymboles.put(gdfc.getSymbole(), value);

				}
			}
		}

		callback.diceFaceChanged(valuePerSymboles);

	}

	public interface CallBack {
		void diceUpdated();

		void diceFaceChanged(HashMap<GameSymbole, Float> deltaSymboles);

		void diceCanceled();
	}

}
